package com.xd.core.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.XkdException;
import com.xd.common.util.OrderNumUtil;
import com.xd.common.util.RSAUtils;
import com.xd.core.api.controller.ApiContractController;
import com.xd.core.api.dto.SignContractDto;
import com.xd.core.api.entity.CardProtocolInfo;
import com.xd.core.api.mapper.CardProtocolInfoMapper;
import com.xd.core.api.service.ApiContractService;
import com.xd.core.business.dto.*;
import com.xd.core.business.entity.*;
import com.xd.core.business.mapper.*;
import com.xd.core.business.service.ICreditService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xd.core.business.service.IIncomingInfoService;
import com.xd.core.business.vo.IncomingInfoInsuranceVo;
import com.xd.core.company.entity.Company;
import com.xd.core.company.mapper.CompanyMapper;
import com.xd.core.debt.dto.Review;
import com.xd.core.h5.vo.AddSignerVo;
import com.xd.core.h5.vo.AdvanceRepaymentDetail;
import com.xd.core.h5.vo.CarInsuranceDetail;
import com.xd.core.business.vo.RepaymentInsuranceSchedule;
import com.xd.core.note.IAsyncService;
import com.xd.core.product.entity.Product;
import com.xd.core.product.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 授信表 服务实现类
 * </p>
 *
 * @author ZX
 * @since 2025-02-23
 */
@Slf4j
@Service
public class CreditServiceImpl extends ServiceImpl<CreditMapper, Credit> implements ICreditService {
    @Autowired
    private IncomingInfoMapper incomingInfoMapper;
    @Autowired
    private IIncomingInfoService iIncomingInfoService;
    @Autowired
    private IncomingCommonLoanMapper incomingCommonLoanMapper;
    @Autowired
    private IncomingUrgentContactMapper incomingUrgentContactMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private CreditMapper creditMapper;
    @Autowired
    private CertificationMapper certificationMapper;
    @Autowired
    private IncomingInfoSuppMapper incomingInfoSuppMapper;
    @Autowired
    private CardProtocolInfoMapper cardProtocolInfoMapper;
    @Autowired
    private IAsyncService iAsyncService;
    @Autowired
    private OutInfoMapper outInfoMapper;
    @Autowired
    private ApiContractService apiContractService;
    @Autowired
    private CompanyMapper companyMapper;

    @Value("${h5rsakey.publicKey}")
    private String publicKey;
    @Autowired
    private CarCreditMapper carCreditMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateCredit(CreditDto creditDto) {
        Integer incomingId = creditDto.getIncomingId();
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);
        if (SysConstant.ORDER_DISABLE.equals(incomingInfo.getIsEnable())) {
            throw new XkdException("该订单已被平台停用");
        }
        //验证车贷字段长度
        Product product = productMapper.selectById(creditDto.getProductId());
        if (SysConstant.PRODUCT_TWO.equals(product.getType())){
            iIncomingInfoService.validateCarLoanFields(BeanUtil.copyProperties(creditDto, IncomingInfoDto.class));
        }
        BigDecimal amount = creditDto.getAmount();

        if (product.getMinAmount().compareTo(amount) > 0 || product.getMaxAmount().compareTo(amount) < 0) {
            throw new XkdException("授信金额超出产品贷款额度");
        }
        //主借人三要素认证
        iIncomingInfoService.threeElementAuthentication(creditDto.getIdCard(), creditDto.getName(), creditDto.getPhone());
        //担保人三要素认证
        iIncomingInfoService.threeElementAuthentication(creditDto.getGuarantorIdCard(), creditDto.getGuarantorName(), creditDto.getGuarantorPhone());

        //新增授信信息
        Credit credit = BeanUtil.copyProperties(creditDto, Credit.class);
        credit.setUserId(incomingInfo.getManageUserId());
        if (!incomingInfo.getStatus().equals(SysConstant.BUSINESS_STATUS_FIVE)) {
            String status;
            //修改进件表状态为授信成功
            if (SysConstant.CREDIT_SUCCESS.equals(creditDto.getStatus())) {
                status = SysConstant.BUSINESS_STATUS_FIVE;
                BeanUtil.copyProperties(creditDto, incomingInfo);
                incomingInfo.setStatus(status);
                incomingInfoMapper.updateById(incomingInfo);
            } else {
                status = SysConstant.BUSINESS_STATUS_FOUR;
                BeanUtil.copyProperties(creditDto, incomingInfo);
                incomingInfo.setStatus(status);
                incomingInfoMapper.updateById(incomingInfo);
                return;
            }
            IncomingInfoSupp incomingInfoSupp = BeanUtil.copyProperties(creditDto, IncomingInfoSupp.class);
            incomingInfoSuppMapper.updateById(incomingInfoSupp);
            List<IncomingCommonLoan> incomingCommonLoans = creditDto.getIncomingCommonLoans();
            List<IncomingUrgentContact> incomingUrgentContacts = creditDto.getIncomingUrgentContacts();

            //删除原来的共同贷款人,再新增
            if (CollectionUtil.isNotEmpty(incomingCommonLoans)) {
                incomingCommonLoanMapper.deleteById(incomingId);
                //用户三要素认证
                for (IncomingCommonLoan loan : incomingCommonLoans) {
                    //用户三要素认证
                    iIncomingInfoService.threeElementAuthentication(loan.getIdCard(), loan.getName(), loan.getPhone());
                }
                incomingCommonLoanMapper.batchInsert(incomingCommonLoans);
            }
            //修改紧急联系人
            if (CollectionUtil.isNotEmpty(incomingUrgentContacts)) {
                incomingUrgentContactMapper.deleteById(incomingId);
                incomingUrgentContactMapper.batchInsert(incomingUrgentContacts);
            }


            CardProtocolInfo cardProtocolInfo = cardProtocolInfoMapper.selectOne
                    (new LambdaQueryWrapper<CardProtocolInfo>().eq(CardProtocolInfo::getRepayAccount, creditDto.getReceivingAccount()));
            if (ObjectUtil.isNull(cardProtocolInfo)) {
                credit.setCardStatus("0");
            } else {
                credit.setCardStatus("1");
            }
            credit.setRepayName(creditDto.getAccountName());
            credit.setRepayAccount(creditDto.getReceivingAccount());
            credit.setRepayBank(creditDto.getBank());
            credit.setAmountRest(credit.getAmount());
            save(credit);
        } else {
            throw new XkdException("授信完成后不允许再次编辑");
        }
    }

    @Override
    public void insertContracts(Integer incomingId) {
        //删除之前存在的合同(包括借款,抵押等合同)
        contractMapper.delete(new LambdaQueryWrapper<Contract>().
                eq(Contract::getIncomingId, incomingId)
                .in(Contract::getType, SysConstant.CONTRACT_TYPE_TOW,
                        SysConstant.CONTRACT_TYPE_SEVEN, SysConstant.CONTRACT_TYPE_FIVE, SysConstant.CONTRACT_TYPE_THREE));
        // 查询入库信息
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);


        // 保存签约合同信息
        List<Contract> contracts = new ArrayList<>();

        // 创建合同
        createAndAddContract(contracts, incomingId, incomingInfo.getCompanyId(), SysConstant.CONTRACT_TYPE_TOW);
        createAndAddContract(contracts, incomingId, incomingInfo.getCompanyId(), SysConstant.CONTRACT_TYPE_SEVEN);


        if (ObjectUtil.isEmpty(incomingInfo)) {
            throw new XkdException("入库信息不存在，ID: " + incomingId);
        }

        // 如果有担保人，添加担保合同
        if (incomingInfo.getGuarantorName() != null && !incomingInfo.getGuarantorName().isEmpty()) {
            createAndAddContract(contracts, incomingId, incomingInfo.getCompanyId(), SysConstant.CONTRACT_TYPE_FIVE);
        }

        // 查询产品信息
        Product product = productMapper.selectById(incomingInfo.getProductId());
        if (ObjectUtil.isEmpty(incomingInfo)) {
            throw new XkdException("产品信息不存在，ID: " + incomingInfo.getProductId());
        }

        // 如果产品类型不是PRODUCT_ONE，添加抵押合同
        if (!SysConstant.PRODUCT_ONE.equals(product.getType())) {
            createAndAddContract(contracts, incomingId, incomingInfo.getCompanyId(), SysConstant.CONTRACT_TYPE_THREE);
        }

        // 批量插入合同
        contractMapper.batchInsert(contracts);
    }

    @Override
    public void updateCreditFail(CreditDto creditDto) {
        Integer incomingId = creditDto.getIncomingId();
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);
        if (SysConstant.ORDER_DISABLE.equals(incomingInfo.getIsEnable())) {
            throw new XkdException("该订单已被平台停用");
        }
        if (!incomingInfo.getStatus().equals(SysConstant.BUSINESS_STATUS_FIVE)) {
            String status = SysConstant.BUSINESS_STATUS_FOUR;
            incomingInfo.setStatus(status);
            incomingInfoMapper.updateStatus(status, incomingId);
        }
    }

    @Override
    public void updateCreditAccount(CreditContractDto creditContractDto) {
        Integer incomingId = creditContractDto.getIncomingId();
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);
        if (SysConstant.ORDER_DISABLE.equals(incomingInfo.getIsEnable())) {
            throw new XkdException("该订单已被平台停用");
        }
        //验证支付通道
        Company company = companyMapper.selectById(creditContractDto.getCompanyId());
        String thoroughFare = company.getThoroughFare();
        String payPass = creditContractDto.getPayPass();
        if (!thoroughFare.contains(payPass)) {
            throw new XkdException("资方公司未配置该支付通道");
        }
        Integer creditId = creditContractDto.getCreditId();
        Credit credit = getById(creditId);

        BigDecimal amountRest = credit.getAmountRest();
        Product product = productMapper.selectById(incomingInfo.getProductId());
        //校验授信金额，利率，贷款期限，还款方式,剩余授信金额
        BigDecimal rate = creditContractDto.getRate();
        String repayFrequency = creditContractDto.getRepayFrequency();
        String repayType = creditContractDto.getRepayType();
        if (!product.getRepayment().contains(repayType)) {
            throw new XkdException("贷款方式不符合产品贷款方式");
        }

        if (product.getRateMin().compareTo(rate) > 0 || product.getRateMax().compareTo(rate) < 0) {
            throw new XkdException("贷款利率超出产品贷款利率");
        }
        Integer term = creditContractDto.getTerm();
        if (SysConstant.REPAY_FREQUENCY_DAY.equals(repayFrequency)) {

            if (product.getLoanTermMinDay().compareTo(term) > 0 || product.getLoanTermMaxDay().compareTo(term) < 0) {
                throw new XkdException("贷款期限超出产品贷款期限");
            }
        } else if(SysConstant.REPAY_FREQUENCY_WEEK.equals(repayFrequency)){
            if (product.getLoanTermMinMonth().compareTo(term) > 0 || product.getLoanTermMaxMonth().compareTo(term) < 0) {
                throw new XkdException("贷款期限超出产品贷款期限");
            }
        }else {
            if (product.getLoanTermMinMonth().compareTo(term) > 0 || product.getLoanTermMaxMonth().compareTo(term) < 0) {
                throw new XkdException("贷款期限超出产品贷款期限");
            }
        }
        BigDecimal outLoan = creditContractDto.getOutLoan();
        if (outLoan.compareTo(amountRest) > 0) {
            throw new XkdException("申请提现金额不能超过剩余授信金额");
        }
        if (creditContractDto.getOutLoan().compareTo(product.getMaxAmount()) > 0 || creditContractDto.getOutLoan().compareTo(product.getMinAmount()) < 0) {
            throw new XkdException("申请提现金额超出产品金额范围");
        }
        //更新剩余授信金额
        creditMapper.updateCreditAmountRest(outLoan, creditId);
        //生成放款表,修改状态待签约
        OutInfo outInfo = BeanUtil.copyProperties(creditContractDto, OutInfo.class);
        outInfo.setLoanMethod(creditContractDto.getRepayType());
        outInfoMapper.insert(outInfo);
        SignContractDto signContractDto = new SignContractDto();
        if(SysConstant.CONTROVERSY_ONE.equals(creditContractDto.getControversy())){
            //生成公证表数据
            Certification certification = new Certification();
            certification.setOutId(outInfo.getOutId());
            certification.setIncomingId(incomingId);
            certification.setStartTime(new Date());
            certificationMapper.insert(certification);
            signContractDto.setCertificationId(certification.getCertificationId());
        }
        signContractDto.setOutId(outInfo.getOutId());
        signContractDto.setIncomingId(incomingId);
        signContractDto.setUsed(outInfo.getUsed());
        signContractDto.setLoanAmount(outInfo.getOutLoan());
        signContractDto.setRepayFrequency(outInfo.getRepayFrequency());
        signContractDto.setTerm(outInfo.getTerm());
        signContractDto.setRate(outInfo.getRate());
        signContractDto.setLoanMethod(creditContractDto.getRepayType());
        signContractDto.setControversy(outInfo.getControversy());
        signContractDto.setCityRemark(outInfo.getCityRemark());
        signContractDto.setPayPass(outInfo.getPayPass());
        signContractDto.setCreditId(creditId);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {//事务提交完成后执行
                if (creditContractDto.getControversy().equals(SysConstant.CONTROVERSY_ONE)){//是否公证
                    iAsyncService.notarizationContract(signContractDto);
                }else {
                    iAsyncService.signContract(signContractDto);
                }
            }
        });
    }

    @Override
    public void updateInsuranceCredit(CreditInsuranceDto creditDto) {
        Integer incomingId = creditDto.getIncomingId();
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);
        if (SysConstant.ORDER_DISABLE.equals(incomingInfo.getIsEnable())) {
            throw new XkdException("该订单已被平台停用");
        }
        Integer count1 = carCreditMapper.selectCount(new LambdaQueryWrapper<CarCredit>().eq(CarCredit::getIncomingId, incomingId)
                .isNotNull(CarCredit::getDrivingUrl).isNotNull(CarCredit::getInsuranceUrl));
        if (count1==0){
            throw new XkdException("投保单或行驶证上传不齐，请重新提交");
        }
        //新增授信信息
        Credit credit = BeanUtil.copyProperties(creditDto, Credit.class);
        credit.setUserId(incomingInfo.getManageUserId());
        //验证产品贷款金额，贷款期限
        Integer loanTerm = creditDto.getTerm();
        Product product = productMapper.selectById(0);
        if (product.getLoanTermMinMonth().compareTo(loanTerm) > 0 || product.getLoanTermMaxMonth().compareTo(loanTerm) < 0) {
            throw new XkdException("贷款期限超出产品贷款期限");
        }
        BigDecimal outLoan = creditDto.getLoanAmount();
        BigDecimal minAmount = product.getMinAmount();
        BigDecimal maxAmount = product.getMaxAmount();
        if (outLoan.compareTo(minAmount) < 0 || outLoan.compareTo(maxAmount) > 0) {
            throw new XkdException("贷款金额超出产品金额限制");
        }
        if (!incomingInfo.getStatus().equals(SysConstant.BUSINESS_STATUS_FIVE)) {
            //计算综合年化利率
            BigDecimal rate = null;
            BigDecimal term = BigDecimal.valueOf(loanTerm);
            String chargeModel = creditDto.getChargeModel();
            if (SysConstant.INSURANCE_FEE_TYPE_ZERO.equals(chargeModel)) {
                rate = BigDecimal.ZERO;
            } else if (SysConstant.INSURANCE_FEE_TYPE_ONE.equals(chargeModel)) {
                BigDecimal postServiceFeeRate = creditDto.getPostServiceFeeRate();
                rate = postServiceFeeRate.multiply(new BigDecimal(12)).divide(term, 4, RoundingMode.HALF_UP);
            } else {
                BigDecimal loanAmount = creditDto.getLoanAmount();
                BigDecimal preServiceFee = creditDto.getPreServiceFee();
                BigDecimal postServiceFee = creditDto.getPostServiceFee();
                BigDecimal add = preServiceFee.add(postServiceFee);
                rate = add.multiply(new BigDecimal(12)).divide(loanAmount.multiply(term), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            }

            //修改进件表状态为授信成功
//            if (SysConstant.CREDIT_SUCCESS.equals(creditDto.getStatus())) {
            BeanUtil.copyProperties(creditDto, incomingInfo,"status");
            incomingInfoMapper.updateById(incomingInfo);
//            } else {
//                status = SysConstant.BUSINESS_STATUS_THREE;
//                BeanUtil.copyProperties(creditDto,incomingInfo);
//                incomingInfo.setStatus(status);
//                incomingInfoMapper.updateById(incomingInfo);
//                return;
//            }
            //新增或编辑授信信息
            credit.setRate(rate);
            credit.setStatus("0");//等待授信
            Integer count = creditMapper.selectCount(new LambdaQueryWrapper<Credit>().eq(Credit::getIncomingId, incomingId));
            if (count > 0 ){
                creditMapper.update(credit,(new LambdaQueryWrapper<Credit>().eq(Credit::getIncomingId, incomingId)));
            }else {
            save(credit);
            }
        } else {
            throw new XkdException("授信完成后不允许再次编辑");
        }
    }

    public static void main(String[] args) {
        //生成还款账单
        List<RepaymentInsuranceSchedule> schedule = new ArrayList<>();
        Integer loanTerm =6;
        Integer repayDay = 15;

        BigDecimal annualRate =BigDecimal.ZERO;
            annualRate = new BigDecimal("20")
                    .divide(BigDecimal.valueOf(loanTerm),RoundingMode.HALF_UP).multiply(new BigDecimal(12));//后置服务费利率
        // 计算利率
        BigDecimal loanAmount = new BigDecimal(0.18);//本金
        BigDecimal totalInterest = BigDecimal.ZERO;

        BigDecimal remainingPrincipal = loanAmount; // 剩余本金

        // 累计利息
        BigDecimal totalInterestAcc = BigDecimal.ZERO;

        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        Date currentDate = new Date(calendar.getTimeInMillis());

        // 计算首次还款日期
        calendar.setTime(currentDate);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, repayDay);


        // 等额本息
            // 日利率 = 年利率 / 36000
            BigDecimal dayRate = annualRate.divide(BigDecimal.valueOf(36000), 10, RoundingMode.HALF_UP);

            // 月利率 = 年利率 / 12
            BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(1200), 10, RoundingMode.HALF_UP);

            // 每月还款额 X = P * [r(1+r)^n] / [(1+r)^n - 1]
            BigDecimal numerator = monthlyRate.multiply(BigDecimal.ONE.add(monthlyRate).pow(loanTerm));
            BigDecimal denominator = BigDecimal.ONE.add(monthlyRate).pow(loanTerm).subtract(BigDecimal.ONE);
            BigDecimal monthlyPayment = loanAmount.multiply(numerator).divide(denominator, 2, RoundingMode.HALF_UP);

            // 总还款额 = 每月还款额 * 总还款月数
            BigDecimal totalRepayment = monthlyPayment.multiply(BigDecimal.valueOf(loanTerm));

            // 总利息 = 总还款额 - 贷款本金
            totalInterest = totalRepayment.subtract(loanAmount);
            //剩余利息
            BigDecimal remainingInterest = totalInterest;

            // 计算首月实际借款天数
            Calendar loanStartCalendar = Calendar.getInstance();
            loanStartCalendar.setTime(new Date()); // loanStartDate 是放款日期

            int actualDays;

            // 如果放款日是1号，则实际借款天数为30天
            if (loanStartCalendar.get(Calendar.DAY_OF_MONTH) == 1) {
                actualDays = 30; // 固定为30天
            } else {
                // 否则，计算从放款日到月底的实际天数
                actualDays = loanStartCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) - loanStartCalendar.get(Calendar.DAY_OF_MONTH) + 1;
                actualDays += repayDay; // 加上还款日
            }

            // 首月应还利息 = 剩余本金 * 日利率 * 实际借款天数
            BigDecimal firstMonthInterest = remainingPrincipal.multiply(dayRate)
                    .multiply(BigDecimal.valueOf(actualDays))
                    .setScale(2, RoundingMode.HALF_UP);
            //累计利息
            totalInterestAcc = totalInterestAcc.add(firstMonthInterest);
            //剩余利息
            remainingInterest = remainingInterest.subtract(firstMonthInterest);
            // 首月应还本金 = 每月还款额 - 首月应还利息
            BigDecimal firstMonthPrincipal = monthlyPayment.subtract(firstMonthInterest);

            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(firstMonthPrincipal);

            // 设置首月还款日期
            Date firstRepaymentDate = new Date(calendar.getTimeInMillis());

            RepaymentInsuranceSchedule firstPayment = new RepaymentInsuranceSchedule();
            firstPayment.setAmount(monthlyPayment);
            firstPayment.setPrincipal(firstMonthPrincipal);
            firstPayment.setInterest(firstMonthInterest);
            firstPayment.setInstallmentNumber(1);
            firstPayment.setRepaymentDate(firstRepaymentDate);
            firstPayment.setCreateTime(currentDate);
            firstPayment.setPrincipalTodo(firstMonthPrincipal);
            firstPayment.setInterestTodo(firstMonthInterest);
            schedule.add(firstPayment);
            // 按月还款，增加一个月
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, repayDay);

            // 次月及以后的计算
            for (int period = 2; period <= loanTerm - 1; period++) {
                // 每月应还利息 = 剩余本金 * 月利率
                BigDecimal monthlyInterest = remainingPrincipal.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);

                // 每月应还本金 = 每月还款额 - 每月应还利息
                BigDecimal monthlyPrincipal = monthlyPayment.subtract(monthlyInterest);
                //如果剩余利息小于等于每月应还利息，则本月应还利息等于剩余利息
                if (remainingInterest.compareTo(monthlyInterest) <= 0) {
                    monthlyInterest = remainingInterest;
                    monthlyPrincipal = monthlyPayment.subtract(monthlyInterest);
                }
                //累计利息
                totalInterestAcc = totalInterestAcc.add(monthlyInterest);
                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);

                // 设置还款日期
                Date repaymentDate = new Date(calendar.getTimeInMillis());

                RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                remainingInterest = remainingInterest.subtract(monthlyInterest);

                payment.setAmount(monthlyPayment);
                payment.setPrincipal(monthlyPrincipal);
                payment.setInterest(monthlyInterest);
                payment.setInstallmentNumber(period);
                payment.setRepaymentDate(repaymentDate);
                payment.setCreateTime(currentDate);
                payment.setPrincipalTodo(monthlyPrincipal);
                payment.setInterestTodo(monthlyInterest);
                schedule.add(payment);

                // 按月还款，增加一个月
                calendar.add(Calendar.MONTH, 1);
                calendar.set(Calendar.DAY_OF_MONTH, repayDay);
            }

            BigDecimal lastMonth = totalInterest.subtract(totalInterestAcc);
            BigDecimal amount = lastMonth.add(remainingPrincipal);
            Date repaymentDate = new Date(calendar.getTimeInMillis());
            RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
            payment.setAmount(amount);
            payment.setPrincipal(remainingPrincipal);
            payment.setInterest(lastMonth);
            payment.setInstallmentNumber(loanTerm);
            payment.setRepaymentDate(repaymentDate);
            payment.setCreateTime(currentDate);
            payment.setPrincipalTodo(remainingPrincipal);
            payment.setInterestTodo(lastMonth);
            schedule.add(payment);
            System.out.println(schedule);
        }
    @Override
    public CarInsuranceDetail goContract(Integer incomingId) {
        CarInsuranceDetail carInsuranceDetail=creditMapper.selectContract(incomingId);
        //生成还款账单
        List<RepaymentInsuranceSchedule> schedule = new ArrayList<>();
        Integer loanTerm = carInsuranceDetail.getTerm();
        Integer repayDay = carInsuranceDetail.getRepayDay();
        String loanMethod = carInsuranceDetail.getLoanMethodCode();
        BigDecimal insuranceAmount = carInsuranceDetail.getInsuranceAmount();
        BigDecimal annualRate =BigDecimal.ZERO;
        Integer repayDay1 = 0;
        if (!carInsuranceDetail.getChargeModel().equals(SysConstant.CHARGE_MODEL_ZERO)){
             annualRate = carInsuranceDetail.getPostServiceFeeRate()
                     .multiply(new BigDecimal(12)).divide(BigDecimal.valueOf(loanTerm),10,RoundingMode.HALF_UP);//后置服务费利率
        }
        // 计算利率
        BigDecimal loanAmount = carInsuranceDetail.getLoanAmount(); //本金
        BigDecimal totalInterest = BigDecimal.ZERO;

        BigDecimal remainingPrincipal = loanAmount; // 剩余本金

        // 累计利息
        BigDecimal totalInterestAcc = BigDecimal.ZERO;

        // 获取当前日期
        Calendar calendar = Calendar.getInstance();
        Date currentDate = new Date(calendar.getTimeInMillis());

        // 计算首次还款日期
            calendar.setTime(currentDate);
            repayDay1 = repayDay;
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, repayDay1);


        switch (loanMethod) {
            // 等额本金
            case SysConstant.REPAY_TYPE_ZERO: {
                // 日利率 = 年利率 / 36000
                BigDecimal dayRate = annualRate.divide(BigDecimal.valueOf(36000), 10, RoundingMode.HALF_UP);

                // 月利率 = 年利率 / 1200
                BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(1200), 10, RoundingMode.HALF_UP);

                // 每月应还本金 = 贷款本金 / 总还款月数
                BigDecimal monthlyPrincipal = loanAmount.divide(BigDecimal.valueOf(loanTerm), 2, RoundingMode.HALF_UP);


                // 计算首月实际借款天数
                Calendar loanStartCalendar = Calendar.getInstance();
                loanStartCalendar.setTime(new Date());

                int actualDays;

                // 如果放款日是1号，则实际借款天数为30天
                if (loanStartCalendar.get(Calendar.DAY_OF_MONTH) == 1) {
                    actualDays = 30; // 固定为30天
                } else {
                    // 否则，计算从放款日到月底的实际天数
                    actualDays = loanStartCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) - loanStartCalendar.get(Calendar.DAY_OF_MONTH) + 1;
                    actualDays += repayDay1; // 加上还款日
                }

                // 首月应还利息 = 剩余本金 × 日利率 × 实际借款天数
                BigDecimal firstMonthInterest = remainingPrincipal.multiply(dayRate)
                        .multiply(BigDecimal.valueOf(actualDays))
                        .setScale(2, RoundingMode.HALF_UP);
                //累计利息
                totalInterestAcc = totalInterestAcc.add(firstMonthInterest);
                totalInterest = totalInterestAcc;
                // 首月应还总额 = 每月应还本金 + 首月应还利息
                BigDecimal firstMonthPayment = monthlyPrincipal.add(firstMonthInterest);

                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);

                // 设置首月还款日期
                Date firstRepaymentDate = new Date(calendar.getTimeInMillis());

                RepaymentInsuranceSchedule firstPayment = new RepaymentInsuranceSchedule();
                firstPayment.setAmount(firstMonthPayment);
                firstPayment.setPrincipal(monthlyPrincipal);
                firstPayment.setInterest(firstMonthInterest);
                firstPayment.setInstallmentNumber(1);
                firstPayment.setRepaymentDate(firstRepaymentDate);
                firstPayment.setCreateTime(currentDate);
                firstPayment.setPrincipalTodo(monthlyPrincipal);
                firstPayment.setInterestTodo(firstMonthInterest);
                firstPayment.setIncomingId(incomingId);
                schedule.add(firstPayment);
                // 按月还款，增加一个月
                calendar.add(Calendar.MONTH, 1);
                calendar.set(Calendar.DAY_OF_MONTH, repayDay1);

                // 次月及以后的计算
                for (int period = 2; period <= loanTerm; period++) {
                    // 每月应还利息 = 剩余本金 × 月利率
                    BigDecimal monthlyInterest = remainingPrincipal.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);

                    // 每月应还总额 = 每月应还本金 + 每月应还利息
                    BigDecimal monthlyPayment = monthlyPrincipal.add(monthlyInterest);
                    totalInterestAcc = totalInterestAcc.add(monthlyInterest);
                    totalInterest = totalInterestAcc;
                    // 更新剩余本金
                    remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);

                    // 设置还款日期
                    Date repaymentDate = new Date(calendar.getTimeInMillis());

                    RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                    payment.setAmount(monthlyPayment);
                    payment.setPrincipal(monthlyPrincipal);
                    payment.setInterest(monthlyInterest);
                    payment.setInstallmentNumber(period);
                    payment.setRepaymentDate(repaymentDate);
                    payment.setCreateTime(currentDate);
                    payment.setPrincipalTodo(monthlyPrincipal);
                    payment.setInterestTodo(monthlyInterest);
                    payment.setIncomingId(incomingId);
                    schedule.add(payment);
                    // 按月还款，增加一个月
                    calendar.add(Calendar.MONTH, 1);
                    calendar.set(Calendar.DAY_OF_MONTH, repayDay1);
                }
                break;
            }
            // 等额本息
            case SysConstant.REPAY_TYPE_ONE: {
                // 日利率 = 年利率 / 36000
                BigDecimal dayRate = annualRate.divide(BigDecimal.valueOf(36000), 10, RoundingMode.HALF_UP);

                // 月利率 = 年利率 / 12
                BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(1200), 10, RoundingMode.HALF_UP);

                // 每月还款额 X = P * [r(1+r)^n] / [(1+r)^n - 1]
                BigDecimal numerator = monthlyRate.multiply(BigDecimal.ONE.add(monthlyRate).pow(loanTerm));
                BigDecimal denominator = BigDecimal.ONE.add(monthlyRate).pow(loanTerm).subtract(BigDecimal.ONE);
                BigDecimal monthlyPayment = loanAmount.multiply(numerator).divide(denominator, 2, RoundingMode.HALF_UP);

                // 总还款额 = 每月还款额 * 总还款月数
                BigDecimal totalRepayment = monthlyPayment.multiply(BigDecimal.valueOf(loanTerm));

                // 总利息 = 总还款额 - 贷款本金
                totalInterest = totalRepayment.subtract(loanAmount);
                //剩余利息
                BigDecimal remainingInterest = totalInterest;

                // 计算首月实际借款天数
                Calendar loanStartCalendar = Calendar.getInstance();
                loanStartCalendar.setTime(new Date()); // loanStartDate 是放款日期

                int actualDays;

                // 如果放款日是1号，则实际借款天数为30天
                if (loanStartCalendar.get(Calendar.DAY_OF_MONTH) == 1) {
                    actualDays = 30; // 固定为30天
                } else {
                    // 否则，计算从放款日到月底的实际天数
                    actualDays = loanStartCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) - loanStartCalendar.get(Calendar.DAY_OF_MONTH) + 1;
                    actualDays += repayDay1; // 加上还款日
                }

                // 首月应还利息 = 剩余本金 * 日利率 * 实际借款天数
                BigDecimal firstMonthInterest = remainingPrincipal.multiply(dayRate)
                        .multiply(BigDecimal.valueOf(actualDays))
                        .setScale(2, RoundingMode.HALF_UP);
                //累计利息
                totalInterestAcc = totalInterestAcc.add(firstMonthInterest);
                //剩余利息
                remainingInterest = remainingInterest.subtract(firstMonthInterest);
                // 首月应还本金 = 每月还款额 - 首月应还利息
                BigDecimal firstMonthPrincipal = monthlyPayment.subtract(firstMonthInterest);

                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(firstMonthPrincipal);

                // 设置首月还款日期
                Date firstRepaymentDate = new Date(calendar.getTimeInMillis());

                RepaymentInsuranceSchedule firstPayment = new RepaymentInsuranceSchedule();
                firstPayment.setAmount(monthlyPayment);
                firstPayment.setPrincipal(firstMonthPrincipal);
                firstPayment.setInterest(firstMonthInterest);
                firstPayment.setInstallmentNumber(1);
                firstPayment.setRepaymentDate(firstRepaymentDate);
                firstPayment.setCreateTime(currentDate);
                firstPayment.setPrincipalTodo(firstMonthPrincipal);
                firstPayment.setInterestTodo(firstMonthInterest);
                firstPayment.setIncomingId(incomingId);
                schedule.add(firstPayment);
                // 按月还款，增加一个月
                calendar.add(Calendar.MONTH, 1);
                calendar.set(Calendar.DAY_OF_MONTH, repayDay1);

                // 次月及以后的计算
                for (int period = 2; period <= loanTerm - 1; period++) {
                    // 每月应还利息 = 剩余本金 * 月利率
                    BigDecimal monthlyInterest = remainingPrincipal.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);

                    // 每月应还本金 = 每月还款额 - 每月应还利息
                    BigDecimal monthlyPrincipal = monthlyPayment.subtract(monthlyInterest);
                    //如果剩余利息小于等于每月应还利息，则本月应还利息等于剩余利息
                    if (remainingInterest.compareTo(monthlyInterest) <= 0) {
                        monthlyInterest = remainingInterest;
                        monthlyPrincipal = monthlyPayment.subtract(monthlyInterest);
                    }
                    //累计利息
                    totalInterestAcc = totalInterestAcc.add(monthlyInterest);
                    // 更新剩余本金
                    remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);

                    // 设置还款日期
                    Date repaymentDate = new Date(calendar.getTimeInMillis());

                    RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                    remainingInterest = remainingInterest.subtract(monthlyInterest);

                    payment.setAmount(monthlyPayment);
                    payment.setPrincipal(monthlyPrincipal);
                    payment.setInterest(monthlyInterest);
                    payment.setInstallmentNumber(period);
                    payment.setRepaymentDate(repaymentDate);
                    payment.setCreateTime(currentDate);
                    payment.setPrincipalTodo(monthlyPrincipal);
                    payment.setInterestTodo(monthlyInterest);
                    payment.setIncomingId(incomingId);
                    schedule.add(payment);

                    // 按月还款，增加一个月
                    calendar.add(Calendar.MONTH, 1);
                    calendar.set(Calendar.DAY_OF_MONTH, repayDay1);
                }

                BigDecimal lastMonth = totalInterest.subtract(totalInterestAcc);
                BigDecimal amount = lastMonth.add(remainingPrincipal);
                Date repaymentDate = new Date(calendar.getTimeInMillis());
                RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                payment.setAmount(amount);
                payment.setPrincipal(remainingPrincipal);
                payment.setInterest(lastMonth);
                payment.setInstallmentNumber(loanTerm);
                payment.setRepaymentDate(repaymentDate);
                payment.setCreateTime(currentDate);
                payment.setPrincipalTodo(remainingPrincipal);
                payment.setInterestTodo(lastMonth);
                payment.setIncomingId(incomingId);
                schedule.add(payment);

                break;
            }
            // 等本等息
            case SysConstant.REPAY_TYPE_TWO: {
                // 月利率 = 年利率 / 12
                BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(1200), 10, RoundingMode.HALF_UP);

                // 每月应还本金 = 贷款本金 / 总还款月数
                BigDecimal monthlyPrincipal = loanAmount.divide(BigDecimal.valueOf(loanTerm), 2, RoundingMode.HALF_UP);


                // 计算首月实际借款天数
                Calendar loanStartCalendar = Calendar.getInstance();
                loanStartCalendar.setTime(new Date());

                int actualDays;

                // 如果放款日是1号，则实际借款天数为30天
                if (loanStartCalendar.get(Calendar.DAY_OF_MONTH) == 1) {
                    actualDays = 30; // 固定为30天
                } else {
                    // 否则，计算从放款日到月底的实际天数
                    actualDays = loanStartCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) - loanStartCalendar.get(Calendar.DAY_OF_MONTH) + 1;
                    actualDays += repayDay1; // 加上还款日
                }

                // 总利息 = 贷款本金 × 月利率 × (还款期数-（(30-首月)/30）)
                totalInterest = insuranceAmount.multiply(monthlyRate)
                        .multiply(BigDecimal.valueOf(loanTerm).subtract(
                                BigDecimal.valueOf(30).subtract(BigDecimal.valueOf(actualDays))
                                        .divide(BigDecimal.valueOf(30), 10, RoundingMode.HALF_UP)
                        ))
                        .setScale(2, RoundingMode.HALF_UP);


                // 首月应还利息 = 贷款本金 × 月利率 × (实际借款天数 / 30)
                BigDecimal firstMonthInterest = insuranceAmount.multiply(monthlyRate)
                        .multiply(BigDecimal.valueOf(actualDays))
                        .divide(BigDecimal.valueOf(30), 2, RoundingMode.HALF_UP);
                totalInterestAcc = totalInterestAcc.add(firstMonthInterest);
                remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);

                // 首月应还总额 = 每月应还本金 + 首月应还利息
                BigDecimal firstMonthPayment = monthlyPrincipal.add(firstMonthInterest);

                // 设置首月还款日期
                Date firstRepaymentDate = new Date(calendar.getTimeInMillis());

                RepaymentInsuranceSchedule firstPayment = new RepaymentInsuranceSchedule();
                firstPayment.setAmount(firstMonthPayment);
                firstPayment.setPrincipal(monthlyPrincipal);
                firstPayment.setInterest(firstMonthInterest);
                firstPayment.setInstallmentNumber(1);
                firstPayment.setRepaymentDate(firstRepaymentDate);
                firstPayment.setCreateTime(currentDate);
                firstPayment.setPrincipalTodo(monthlyPrincipal);
                firstPayment.setInterestTodo(firstMonthInterest);
                firstPayment.setIncomingId(incomingId);
                schedule.add(firstPayment);

                // 按月还款，增加一个月
                calendar.add(Calendar.MONTH, 1);
                calendar.set(Calendar.DAY_OF_MONTH, repayDay1);

                // 次月及以后的计算
                for (int period = 2; period <= loanTerm - 1; period++) {
                    // 每月应还利息 = 贷款本金 × 月利率
                    BigDecimal monthlyInterest = insuranceAmount.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);

                    // 每月应还总额 = 每月应还本金 + 每月应还利息
                    BigDecimal monthlyPayment = monthlyPrincipal.add(monthlyInterest);
                    totalInterestAcc = totalInterestAcc.add(monthlyInterest);
                    remainingPrincipal = remainingPrincipal.subtract(monthlyPrincipal);
                    // 设置还款日期
                    Date repaymentDate = new Date(calendar.getTimeInMillis());

                    RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                    payment.setAmount(monthlyPayment);
                    payment.setPrincipal(monthlyPrincipal);
                    payment.setInterest(monthlyInterest);
                    payment.setInstallmentNumber(period);
                    payment.setRepaymentDate(repaymentDate);
                    payment.setCreateTime(currentDate);
                    payment.setPrincipalTodo(monthlyPrincipal);
                    payment.setInterestTodo(monthlyInterest);
                    payment.setIncomingId(incomingId);
                    schedule.add(payment);

                    // 按月还款，增加一个月
                    calendar.add(Calendar.MONTH, 1);
                    calendar.set(Calendar.DAY_OF_MONTH, repayDay1);
                }
                BigDecimal lastMonth = totalInterest.subtract(totalInterestAcc);
                BigDecimal amount = lastMonth.add(remainingPrincipal);
                Date repaymentDate = new Date(calendar.getTimeInMillis());
                RepaymentInsuranceSchedule payment = new RepaymentInsuranceSchedule();
                payment.setAmount(amount);
                payment.setPrincipal(remainingPrincipal);
                payment.setInterest(lastMonth);
                payment.setInstallmentNumber(loanTerm);
                payment.setRepaymentDate(repaymentDate);
                payment.setCreateTime(currentDate);
                payment.setPrincipalTodo(remainingPrincipal);
                payment.setInterestTodo(lastMonth);
                payment.setIncomingId(incomingId);
                schedule.add(payment);
                break;
            }

        }
        Calendar loanStartCalendar = Calendar.getInstance();
        loanStartCalendar.add(Calendar.MONTH, 1);
        loanStartCalendar.set(Calendar.DAY_OF_MONTH, repayDay);
        carInsuranceDetail.setLatestRepayDate(loanStartCalendar.getTime());
        carInsuranceDetail.setRepaymentInsuranceSchedules(schedule);

        //计算贷款金额
        BigDecimal repayAmount = BigDecimal.ZERO;
        repayAmount = schedule.stream()
                .map(RepaymentInsuranceSchedule::getAmount)
                .reduce(repayAmount, BigDecimal::add);
        carInsuranceDetail.setAmountDue(repayAmount + "");
        log.info(schedule.toString());
        //创建合同
        List<AddSignerVo> addSignerVos = apiContractService.h5SignContract(incomingId, carInsuranceDetail.getAmountDue(), schedule);
        carInsuranceDetail.setAddSignerVos(addSignerVos);
        return carInsuranceDetail;

    }

    @Transactional
    @Override
    public Integer goContractInsurance(Integer incomingId,String payPass) {
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);

        if (SysConstant.ORDER_DISABLE.equals(incomingInfo.getIsEnable())) {
            throw new XkdException("该订单已被平台停用");
        }
        //生成放款
        Credit credit = creditMapper.selectOne(new LambdaQueryWrapper<Credit>().eq(Credit::getIncomingId, incomingId));
        OutInfo outInfo = BeanUtil.copyProperties(credit, OutInfo.class);
        outInfo.setPayPass(payPass);
        Integer count = outInfoMapper.selectCount(new LambdaQueryWrapper<OutInfo>().eq(OutInfo::getIncomingId, incomingId));
        if (count>0){
            return null;
//            throw new XkdException("签署合同已提交,请勿重新提交");
        }
        outInfoMapper.insert(outInfo);
        incomingInfoMapper.updateStatus(SysConstant.BUSINESS_STATUS_SIX,incomingId);
        return outInfo.getOutId();
    }

    @Override
    public AdvanceRepaymentDetail advancePaymentInsurance(Integer incomingId) {
        return creditMapper.advancePaymentInsurance(incomingId);
    }

    @Override
    public IncomingInfoInsuranceVo authorizationApplication(Integer incomingId) {
        return incomingInfoMapper.selectInsuranceDetail(incomingId);
    }

    @Override
    public void updateInsuranceStatus(Review review) {
        Integer incomingId = review.getId();
        String status;
        String creditStatus;
        Integer count = creditMapper.selectCount(new LambdaQueryWrapper<Credit>().eq(Credit::getIncomingId, incomingId));
        if (count == 0){
            throw new XkdException("业务状态异常");
        }
        if("0".equals(review.getStatus())){//审核成功
            status = SysConstant.BUSINESS_STATUS_FIVE;
            creditStatus = "2";
            incomingInfoMapper.updateStatus(status,incomingId);
        }else{
            creditStatus = "1";
        }
        creditMapper.updateStatus(creditStatus,incomingId,review.getRemark());
    }

    @Override
    public CreditInsuranceDto getInsuranceIncomingAndCredit(Integer incomingId) {
        return incomingInfoMapper.getInsuranceIncomingAndCredit(incomingId);
    }

    private void createAndAddContract(List<Contract> contracts, Integer incomingId, Integer companyId, String
            contractType) {
        String contractNo = OrderNumUtil.getContractNo();
        Contract contract = new Contract();
        contract.setIncomingId(incomingId);
        contract.setContractNo(contractNo);
        contract.setStatus("1");
        contract.setCompanyId(companyId);
        contract.setType(contractType);
        contracts.add(contract);
    }
}
